<?php

class Zeal_Object_Construct {

	static $__instance__ = array();

////////////////////////////////////////////////////////////////////////////////
// singleton

	public function getInstance($conf=array(), $name='__singleton__')
	{
		return self::getInstanceAbstract($conf, $name, __CLASS__);
	}

	public function setInstance($obj, $name='__singleton__')
	{
		return self::setInstanceAbstract($obj, $name);
	}



	public function getInstanceAbstract($conf=array(), $name='__singleton__', $class=null)
	{
		if(!array_key_exists($name , self::$__instance__) || !(self::$__instance__[$name])) {
			if($class === null) {
				$class = __CLASS__;
			}
            self::$__instance__[$name] = new $class($conf);
		}
		return self::$__instance__[$name];
	}

	public function setInstanceAbstract($obj, $name='__singleton__')
	{
		self::$__instance__[$name] = $obj;
		return $obj;
	}
//
////////////////////////////////////////////////////////////////////////////////
// construct
	function __construct ($conf = array())
	{
		return $this->__constructAbstract($conf);
	}

	function __constructAbstract($conf = array())
	{
		return $this->__constructConfAbstract($conf);

	}

	function __constructConfAbstract ($conf = array())
	{
		/*
		if ($conf instanceof ObjConf) {
		}
		*/
		if (is_array($conf)) {
			foreach($conf as $key => $val) {
				$this->__set($key, $val);
				/*
				$property = ucfirst($key);
				$this->$property = $val;
				*/
			}
 		}
		return $this;
	}

	function __initConfVal ($val)
	{
		if (is_string($val)) {
			$type = strtoupper(substr($val, 0, 2));
			$name = substr($val, 2);

			if ($type == 'C*') { //class
				if (class_exists($name)) {
					$val = new $name();
				}
			} else if ($type == 'O*') { //object
				global $$name;
				$val = $$name;
			}
		} else if (is_array($val)) {
			if(isset($val['_type_'])) {
				switch(strtoupper($val['_type_'])) {
					case "O*" :
					case "OBJECT" :
						$name = $val['name'];
						global $$name;
						$val = $$name;
						break;
					case "C*" :
					case "CLASS" :
						$name = $val['name'];
						if (class_exists($name)) {
							if ($val['singleton']) {
								$obj = new $name($val['conf']);
								if(method_exists($obj, 'setInstance')) {
									$obj->setInstance($obj);
								}
								$val = $obj;
							} else {
								$obj = new $name($val['conf']);
								
								$namespace = trim($val['namespace']);
								if ($namespace) {
									if(method_exists($obj, 'setInstance')) {
										$obj->setInstance($val, $val['namespace']);
									}
								}
								$val = $obj;
							}
						}
						break;
					default:
						break;
				}
			}
		}

		return $val;
	}

	function __set ($key, $val)
	{
		$val = $this->__initConfVal($val);


		if(substr($key, 0, 1) == '_' && substr($key, -1) == '_' ) {
			$this->$key = $val;
			return;
		}



		$property = ucfirst($key);
		$method = 'set' . $property;
		if (method_exists($this, $method)) {
			$this->$method($val);
		} else {
			$propertyStore = '_' . $property . '_';
			$this->$propertyStore = $val;
		}
	}

	function &__get ($key)
	{
		if(substr($key, 0, 1) == '_' && substr($key, -1) == '_' ) {
			return $this->$key;
		}
		$property = ucfirst($key);
		

		//define defaut property value use function that prefix_name is 'def'
		$propertyStore = '_' . $property . '_';
		if (!isset($this->$propertyStore)) {
			$setMethod = 'set' . $property;
			$defMethod = 'def' . $property;
			if(method_exists($this, $defMethod)) {
				if ($this->$defMethod() !== null) {
					$this->$setMethod($this->$defMethod());
				}
				
			}
		}


		$method = 'get' . $property;
		if (method_exists($this, $method)) {
			$rtn =& $this->$method($val); 
		} else {
			$propertyStore = '_' . $property . '_';
			$rtn =& $this->$propertyStore;
		}
		//must return reference then $this->property = $val would work when return value type;
		return $rtn;
	}

/*
	//you can define function your self

	function &getProperty()
	{
		//must return reference then $this->property = $val would work  when return value type; 
		return $this->_Property_; 
	}

	function setProperty()
	{
		//access protery name  <--> store protery name
		//Property             <--> _Property_;
		//note _Property_ the Second charactor must upper case;
		$this->_Property_; 
	}

	function defProperty()
	{
		return "default value"; 
	}
*/

	function __call ($name, $args)
	{
		$pass = $this->__callAccessorAbstract($name, $args);
		if ($pass['dispatched']) {
			return $pass['return'];
		}
	}

	function __callAccessorAbstract ($name, $args)
	{
		$rtn = array();
		$rtn['dispatched'] = false;
		$rtn['return'] = null;

		$type = substr($name, 0, 3);
		$property = ucfirst(substr($name, 3));
		if ($type=="get") {
			$rtn['dispatched'] = true;
			$rtn['return'] = $this->$property;
			return $rtn;
		}
		if ($type=="set") {
			$this->$property = $args[0];
			$rtn['dispatched'] = true;
			$rtn['return'] = null;
			
			return $rtn;
		}

		return $rtn;
	}

	function toArray()
	{
		$rtn = array();
		foreach($this as $key => $val) {
			$key = substr($key, 1, -1);
			$rtn[$key] = $val;
		}
		return $rtn;
	}

	function toString()
	{
		$rtn = '';
		return $rtn;
	}

	function __toString()
	{
		return $this->toString();
	}

	function defPro1 ()
	{
		return 222;
	}

	function test ()
	{
		$this->Pro1 = 444;
	}
}//class end
?> 